`timescale 1ns / 1ps
`include "Func.v"
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/04/21 17:03:03
// Design Name: 
// Module Name: IFU
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
`define E203_XLEN 32
`define E203_ADDR_SIZE 32

module IFU (
    // System	
    input                         nice_clk            ,
    input                         nice_rst_n	      ,
    output                        nice_active	      ,
    output                        nice_mem_holdup     ,//avoid memory read or write by other devices
    //    output                      nice_rsp_err_irq,
    // Control cmd_req
    input                         nice_req_valid       ,//E203 send a nice request
    output                        nice_req_ready       ,//nice can receive request
    input  [`E203_XLEN-1:0]       nice_req_inst        ,//custom instruction
    input  [`E203_XLEN-1:0]       nice_req_rs1         ,//the register 1
    input  [`E203_XLEN-1:0]       nice_req_rs2         ,//the register 2
    // Control cmd_rsp	
    output                        nice_rsp_valid       ,//nice send response
    input                         nice_rsp_ready       ,//e203 can receive response
    //NICE接口信号中，有两个数据传输信号： nice_rsp_rdat和nice_icb_cmd_wdata。这两个信号对应不同的寄存器。
    output [`E203_XLEN-1:0]       nice_rsp_rdat        ,//compute result ,nice_rsp_rdat对应每一行的相加结果，且每次ROWSUM计算完成后均通过nice_rsp_rdat上传结果，这是通过RD寄存器，不会涉及memory的操作
    output                        nice_rsp_err         ,//nice has error
    // Memory lsu_req	
    output                        nice_icb_cmd_valid   ,//nice send a memory request
    input                         nice_icb_cmd_ready   ,//e203 can receive memory request
    output [`E203_ADDR_SIZE-1:0]  nice_icb_cmd_addr    ,//memory request address
    output                        nice_icb_cmd_read    ,//0:write 1:read
    output [`E203_XLEN-1:0]       nice_icb_cmd_wdata   ,//write data request，是NICE与memory之间传输的数据，首先读取RS寄存器中存储的内存地址，随后完成对应内存地址的数据读写
    //    output [`E203_XLEN_MW-1:0]  nice_icb_cmd_wmask   ,
    output [1:0]                  nice_icb_cmd_size    ,//00:byte 01:half-word 10:word
    // Memory lsu_rsp	
    input                         nice_icb_rsp_valid   ,//e203 send memory response
    output                        nice_icb_rsp_ready   ,//nice can receive memory
    input  [`E203_XLEN-1:0]       nice_icb_rsp_rdata   ,//the data read from memory
    input                         nice_icb_rsp_err     ,//error during memory access

    //Decoder Interface
    output [21:0]       inst,
//    output [21:0]       sha_inst,
    output              Start_Decode,
//    output              sha_Start_Decode,

    //RAM1 Interface
    output wire R1_read,R1_write,R2_read,R2_write,
    output wire [8: 0] R1_trans_addra,
    output wire [8: 0] R2_trans_addra,
    output wire R1_trans_ena,R1_trans_wea,R2_trans_ena,R2_trans_wea,
    output wire  [95:0] R1_trans_Dina, R2_trans_Dina,
    input  wire [95:0] R1_DoutA,R2_DoutA,

    input       SHA3_busy,
    input [3:0] sha_dst, 
    input       Poly_busy

);

    //FSM
    parameter IDLE = 3'b001,LOAD = 3'b010,STORE = 3'b011,STORE_Buffer1 = 3'b100,EXU = 3'b101,RSP_VAILD = 3'b111;
    reg [2:0] next_state,current_state;


    reg [31:0] inst_ifu;

    wire nice_req_hsked;
    wire nice_rsp_hsked;
    wire [6:0] opcode;
    wire [6:0] opcode_idle;
    wire OITF;

    assign opcode_idle = nice_req_inst[6:0]; //opcode是前7位
    // wire opcode_custom0_idle = (opcode_idle == 7'b0001011); //SHA3 使用了custom0型的RISC-V指令
    // wire opcode_custom1_idle = (opcode_idle == 7'b0101011); //Poly 使用了custom1型的RISC-V指令
    wire opcode_custom3_idle = (opcode_idle == 7'b1111011); //Load/Store 使用了custom3型的RISC-V指令

    wire func7_load_store_idle = nice_req_inst[31]; //1 STORE/ 0 LOAD
    wire func7_load_store_ram_idle = nice_req_inst[30]; //1 RAM2/ 0 RAM1
    wire func7_load_store_wait_idle = nice_req_inst[29]; //1 WAIT/ 0

    wire wait_inst = opcode_custom3_idle & func7_load_store_wait_idle & nice_req_hsked;
    wire load_inst = opcode_custom3_idle & ~func7_load_store_idle & nice_req_hsked & ~wait_inst;
    wire store_inst = opcode_custom3_idle & func7_load_store_idle & nice_req_hsked & ~wait_inst;
    
    wire RAM1_ena_idle = ~func7_load_store_ram_idle & (load_inst | store_inst);
    wire RAM2_ena_idle = func7_load_store_ram_idle & (load_inst | store_inst);

    wire load_store_en = ~SHA3_busy & ~Poly_busy;


    wire opcode_custom0 = (opcode == 7'b0001011); //SHA3 使用了custom0型的RISC-V指令
    wire opcode_custom1 = (opcode == 7'b0101011); //Poly 使用了custom1型的RISC-V指令
    wire opcode_custom3 = (opcode == 7'b1111011); //Load/Store 使用了custom3型的RISC-V指令

    //LOAD/STORE RAM选择
    wire RAM1_ena = (current_state == LOAD | current_state == STORE_Buffer1 | current_state == STORE) & ~inst_ifu[30];
    wire RAM2_ena = (current_state == LOAD | current_state == STORE_Buffer1 | current_state == STORE) & inst_ifu[30];

    //FSM
    always@(posedge nice_clk or negedge nice_rst_n)
    begin
        if(!nice_rst_n) current_state <= IDLE;
        else current_state <= next_state;
    end

    always @(*) begin
        case(current_state) 
            IDLE : next_state = nice_req_hsked ? (wait_inst ? EXU : load_inst ? LOAD : store_inst ? STORE_Buffer1 : EXU): IDLE;
            LOAD : next_state = nice_rsp_valid ? RSP_VAILD : LOAD;
            STORE_Buffer1 : next_state = STORE;
            STORE : next_state = nice_rsp_valid ? RSP_VAILD : STORE;
            EXU : next_state = nice_rsp_valid ? RSP_VAILD : EXU;
            RSP_VAILD : next_state = IDLE;
            default : next_state = IDLE;
        endcase
    end
    
    //IFU
   always@(posedge nice_clk or negedge nice_rst_n)
   begin
       if(!nice_rst_n) inst_ifu <= 32'b0;
       else if(nice_req_hsked) inst_ifu <= nice_req_inst;
       else inst_ifu <= inst_ifu;
   end
   
   // Control cmd_req
   assign nice_req_hsked = nice_req_valid & nice_req_ready;//命令请求握手
   //nice发出的命令请求握手信号
   assign nice_req_ready = (current_state == IDLE);
   

   //Load
    reg  [2:0] buffer_full_cnt;
    reg  [2:0] buffer_address_cnt;
    wire [2:0] buffer_full_num;

    reg  [7:0] load_store_cnt;
    wire [7:0] load_store_num;
    
    reg  [95:0] data_buffer;
    reg  [`E203_ADDR_SIZE-1:0] nice_icb_cmd_addr_next;
    reg  [8:0] trans_addra_next;

    wire buffer_full;
    wire buffer_address_full;
    wire load_store_state = current_state == LOAD | current_state == STORE;
    wire stop_load_store =  load_store_state ? (load_store_cnt >= load_store_num) ? 1 : 
                            0 :
                            0; 

    //需要load或store的行数 
    assign load_store_num = inst_ifu[28:26] == 1 ? 4 : 
                            inst_ifu[28:26] == 2 ? 32 :
                            inst_ifu[28:26] == 3 ? 64 :
                            inst_ifu[28:26] == 4 ? 96 :
                            inst_ifu[28:26] == 5 ? 128 :
                            0; 

    //load和store的行数计数器
    always @ (posedge nice_clk or negedge nice_rst_n) begin
        if(!nice_rst_n) 
            load_store_cnt <= 0;
        else if(current_state == RSP_VAILD)
            load_store_cnt <= 0;
        else if(load_store_state & buffer_full)
            load_store_cnt <= load_store_cnt + 1;
        else
            load_store_cnt <= load_store_cnt;
    end

    //nice_icb_cmd_addr访问地址每次加4（32位访问）
    always @ (posedge nice_clk or negedge nice_rst_n) begin
        if(!nice_rst_n) 
            nice_icb_cmd_addr_next <= 0;
        else if(current_state == RSP_VAILD)
            nice_icb_cmd_addr_next <= 0;
        else if(load_inst) 
            nice_icb_cmd_addr_next <= nice_req_rs1 + 4;
        else if(store_inst) 
            nice_icb_cmd_addr_next <= nice_req_rs1;
        else if(load_store_state)
            nice_icb_cmd_addr_next <= nice_icb_cmd_addr_next + 4;
        else
            nice_icb_cmd_addr_next <= nice_icb_cmd_addr_next;
    end

    //1是seed,2是公私钥密文,R1的初始地址
    wire [8:0] trans_addra_idle =   (load_inst | store_inst) ? nice_req_inst[25] == 0 ? {3'b100,nice_req_inst[10:7],2'b0} :
                                                                                        {nice_req_inst[10:7],5'b0} : 
                                                                                        0;

    wire trans_addra_full = (current_state == LOAD) ? buffer_full : buffer_address_full;

    //R1 Address
    always @ (posedge nice_clk or negedge nice_rst_n) begin
        if(!nice_rst_n) 
            trans_addra_next <= 0;
        else if(current_state == RSP_VAILD)
            trans_addra_next <= 0;
        else if(load_inst | store_inst) 
            trans_addra_next <= trans_addra_idle;
        else if(trans_addra_full)    
            trans_addra_next <= trans_addra_next + 1;
        else
            trans_addra_next <= trans_addra_next;
    end

    //64位需要填充移位2次，96位需要填充移位3次，   0 64位 / 1 96位
    assign buffer_full_num  =   inst_ifu[25] ? 3 : 2 ;
    
    //只在LOAD/STORE阶段有效
    assign buffer_full = load_store_state ? buffer_full_cnt == buffer_full_num : 0;

    always @ (posedge nice_clk or negedge nice_rst_n) begin
        if(!nice_rst_n) 
            buffer_full_cnt <= 0;
        else if((current_state == RSP_VAILD))
            buffer_full_cnt <= 0;
        else if(load_store_state & buffer_full)
            buffer_full_cnt <= 1;
        else if((load_store_state | current_state == STORE_Buffer1) & ~stop_load_store) 
            buffer_full_cnt <= buffer_full_cnt + 1;
        else
            buffer_full_cnt <= buffer_full_cnt;
    end

    assign buffer_address_full  =  (current_state == STORE | current_state == STORE_Buffer1 | store_inst) ? (buffer_address_cnt == buffer_full_num - 1) : 0;

    always @ (posedge nice_clk or negedge nice_rst_n) begin
        if(!nice_rst_n) 
            buffer_address_cnt <= 0;
        else if((current_state == RSP_VAILD))
            buffer_address_cnt <= 0;
        else if(buffer_address_full)
            buffer_address_cnt <= 0;
        else if((current_state == STORE | current_state == STORE_Buffer1 | store_inst) & ~stop_load_store) 
            buffer_address_cnt <= buffer_address_cnt + 1;
        else
            buffer_address_cnt <= buffer_address_cnt;
    end


    always @ (posedge nice_clk or negedge nice_rst_n) begin
        if(!nice_rst_n) 
            data_buffer <= 96'b0;
        else if(current_state == LOAD) begin
            case(inst_ifu[25])
                0 : data_buffer <= {32'b0,nice_icb_rsp_rdata,data_buffer[63:32]};
                1 : data_buffer <= {nice_icb_rsp_rdata,data_buffer[95:64],data_buffer[63:32]};
                default : data_buffer <= 96'b0;          
            endcase
        end
        else
            data_buffer <= 96'b0;
    end

    wire R1_sel = (RAM1_ena | RAM1_ena_idle);
    wire R2_sel = (RAM2_ena | RAM2_ena_idle);

    //RAM1 Interface
    assign R1_trans_ena     =   R1_sel ? 1 : 0 ;
    assign R1_write         =   R1_sel ? (current_state == LOAD) : 0;
    assign R1_read          =   R1_sel ? (current_state == STORE | current_state == STORE_Buffer1 | store_inst) : 0;
    assign R1_trans_addra   =   (load_store_state | current_state == STORE_Buffer1) ? trans_addra_next : 
                                store_inst ? trans_addra_idle : 0;
    assign R1_trans_wea     =   (current_state == LOAD) ? buffer_full : 0;
    assign R1_trans_Dina    =   data_buffer;

    //RAM2 Interface
    assign R2_trans_ena     =   R2_sel ? 1 : 0;
    assign R2_write         =   R2_sel ? (current_state == LOAD) : 0;
    assign R2_read          =   R2_sel ? (current_state == STORE | current_state == STORE_Buffer1 | store_inst) : 0;
    assign R2_trans_addra   =   (load_store_state | current_state == STORE_Buffer1) ? trans_addra_next : 
                                store_inst ? trans_addra_idle : 0;
    assign R2_trans_wea     =   (current_state == LOAD)  ? buffer_full : 0;
    assign R2_trans_Dina    =   data_buffer;



   // Control cmd_rsp
   assign nice_rsp_hsked = nice_rsp_valid & nice_rsp_ready; //命令响应握手
   assign nice_icb_rsp_hsked = nice_icb_rsp_valid & nice_icb_rsp_ready;//储存响应握手
   //（当前状态lbuf，lbuf计数值为最后值，E203发出储存响应信号）或（当前状态sbuf，sbuf计数值为最后值，E203发出储存响应信号）或（当前状态rowsum，rcv_data_buf_idx计数值为最后值，rowsum_acc_flg为低）或（rcv_data_buf_idx非零，且上个周期的状态为rowsum时（储存响应握手或E203发出nice_rsp_ready信号））
   assign nice_rsp_valid =  (current_state == EXU) ?  
                            opcode_custom0 ? (~SHA3_busy ? 1 : 0) : 
                            opcode_custom1 ? (~Poly_busy & ~OITF ? 1 : 0) :
                            opcode_custom3 ? (~SHA3_busy & ~Poly_busy) ? 1 : 0:
                            0 : 
                            load_store_state ? (stop_load_store ? 1 : 0) :
                            0 ;
   assign nice_rsp_rdat  = 0;//

   // memory access bus error
   //assign nice_rsp_err_irq  =   (nice_icb_rsp_hsked & nice_icb_rsp_err)
   //                          | (nice_req_hsked & illgel_instr)
   //                          ; 
   assign nice_rsp_err   =   (nice_icb_rsp_hsked & nice_icb_rsp_err);//储存响应握手且在访问memory时出错

   // Memory lsu，memory相关
//   assign nice_icb_rsp_ready = (current_state == LOAD) | ((current_state == IDLE & opcode_custom3_idle & nice_req_hsked) & nice_rsp_ready); 
   // rsp always ready
   assign nice_icb_rsp_ready = 1'b1; //始终为1'b1
   //
   assign nice_icb_cmd_valid = (load_store_state | load_inst) & ~stop_load_store ? 1 : 0;
   assign nice_icb_cmd_addr  = load_inst ? nice_req_rs1 : nice_icb_cmd_addr_next;//
   assign nice_icb_cmd_read  = (current_state == LOAD) | load_inst ? 1 : 0;//

   wire [95:0] nice_icb_RAM_Dout = R2_trans_ena ? R2_DoutA : R1_DoutA;
   //Store数据的时候，32位写。
   assign nice_icb_cmd_wdata = (current_state == STORE) ?   buffer_full_cnt == 1 ? nice_icb_RAM_Dout[31:0] :
                                                            buffer_full_cnt == 2 ? nice_icb_RAM_Dout[63:32] :
                                                            buffer_full_cnt == 3 ? nice_icb_RAM_Dout[95:64] : 
                                                            0 :
                                                            0; 

    //2代表4字节32位宽数据 1代表16位宽数据
   assign nice_icb_cmd_size  = 2'b10;
   assign nice_mem_holdup    = load_store_state ? 1 : 0; //LOAD/STORE状态，访问memory锁
   
   // nice_active
   assign nice_active = (current_state != IDLE);

   //Decode
   assign opcode      = inst_ifu[6:0]; //opcode是前7位

   //重组nice指令
   assign inst     = (current_state == RSP_VAILD) & !opcode_custom3 ? {inst_ifu[19],inst_ifu[24],inst_ifu[11],inst_ifu[18:15],inst_ifu[23:20],inst_ifu[10:7],inst_ifu[5],inst_ifu[30:25]} : 0;
   assign Start_Decode = (current_state == RSP_VAILD) & !opcode_custom3;

    wire Poly_RAM1_inst = inst_ifu[30:25] == `NTT | inst_ifu[30:25] == `PWM1 | inst_ifu[30:25] == `PolyAdd;
    assign OITF = (SHA3_busy & Poly_RAM1_inst) ? (sha_dst == inst_ifu[23:20]) : 0;




endmodule
